'use strict';

var net = require("net");
var fs = require('fs');
var querystring = require('querystring');
var http = require('http');
var util = require('util');

var listenConf = {
    port: 7222,
    listenHost: '0.0.0.0'
};

var httpServerConf = {
    //host: '121.40.132.197',
    //host: 'attendance.hfjyyun.net.cn',
    host: '127.0.0.1',
    port: 6004
};

function httpPost(options, parameters, data, callback) {
    var error = null;
    var responseContent = null;

    if ( parameters ) {
        var queryString = querystring.stringify(parameters);
        if ( queryString ) {
            options.path += '?' + queryString;
        }
    }

    options.method = 'POST';

    if ( data ) {
        if ( !options.headers ) {
            options.headers = {};
        }

        options.headers['Content-Length'] = data.length;
    }

    var req = http.request(options, function(res) {
        res.on('data', function(d) {
            responseContent = d.toString('utf8');
            callback(responseContent);
        });
    });

    req.on('error', function(err) {
        console.log(err);
    });

    if ( data ) {
        req.write(data + '\n');
    }
    req.end();
}

function postJSON(path, parameters, obj, callback) {
    var options = {
        hostname: httpServerConf.host,
        port: httpServerConf.port,
        path: path,
        headers: {
            'Content-Type': 'application/json; charset=UTF-8'
        }
    };

    var data = null;
    if ( obj ) {
        data = JSON.stringify(obj);
    }

    httpPost(options, parameters, data, callback);
}

function dataParse(str){
	//var str = buf.toString();
	// todo 检查校验和 以及包头
	if(str.slice(0,3)!='TPJ'){
		console.log("====包头不正确====");
		return;
	}
	var len = parseInt(str.slice(25,29),16);
	var func = str.slice(29,31);
	var order = str.slice(3,7);
	var body = str.slice(31,31+len-2);

	var deviceID = str.slice(7,25);

	var sum = checkSum(func+body);
	if(sum != str.slice(-2)){
		console.log("====校验不通过====");
		return;
	}

	return {
		len : len,
		func : func,
		order : order,
		body : body,
		id : deviceID
	}
}

function checkSum (str){
	console.log(str);
	var sum = 0;
	for(var i=0;i<str.length;i++){
		sum += str.charCodeAt(i);
	}
	sum = sum.toString(16).slice(-2).toUpperCase();
	console.log(sum);
	return sum;
}


function Server(obj,client){
	for(var i in obj){
		this[i] = obj[i];
	}
	this.client = client;
	return this;
}

Server.prototype.handle = function(){
	var handlers = {
		'03' : 'alarm',
		'0C' : 'check_time',
		'10' : 'heartbeat',
		'08' : 'gate_event'
	};
	if(typeof this[handlers[this.func]] =='function'){
		this[handlers[this.func]]();
	}else{
		console.log("尚未处理，功能号:::"+this.func);
	}
};

/**
 * @author wayne  ===16/1/16===
 * @description 回复终端的方法封装，并进行校验
 * @param func:功能号(2) content:包内容(N)
 */

Server.prototype.write = function(func,content){
	var sum = checkSum(func+content);
	var len = func.length + content.length ;
	len = len.toString(16);
	len = '0000'+len;
	len = len.slice(-4);
	var reply = "JTP"+this.order+this.id+len+func+content+sum;
	reply = reply.toUpperCase();
	console.log("回复内容:::"+reply);
	this.client.write(reply);
};

/**
 * @author wayne  ===16/1/16===
 * @description 处理报警信息【4.3】功能号 03
 */

Server.prototype.alarm = function(){
	console.error("收到报警信息:::"+this.body);
	this.write('03','OK');
};


/**
 * @author wayne  ===16/1/16===
 * @description 处理时间校验【4.9】 功能号：0C
 */

Server.prototype.check_time = function(){
	this.write(this.func,this.getTime());
};


/**
 * @author wayne  ===16/1/16===
 * @description 回复心跳包【4.11】 功能号：10
 */

Server.prototype.heartbeat = function(){
	this.write(this.func,'');
};

/**
 * @author wayne  ===16/1/16===
 * @description 进出校门事件【4.6】 功能号：08
 */

Server.prototype.enterSchool = function(deviceId, serialId, time) {
    postJSON('/device/school/enter', null, {
        card: {
            deviceId: deviceId,
            serialId: serialId
        },
        timestamp: time.getTime()
    }, function(data) {
        console.log(data);
    });
}

Server.prototype.exitSchool = function(deviceId, serialId, time) {
    postJSON('/device/school/exit', null, {
        card: {
            deviceId: deviceId,
            serialId: serialId
        },
        timestamp: time.getTime()
    }, function(data) {
        console.log(data);
    });
}

Server.prototype.gate_event = function(){
	console.log("收到进出校门事件:::"+this.body);

    this.processGateEvent(this.body);

	fs.writeFile('result.txt',this.id + '\n',{'flag':'a'},function(err){
		if(err){
			throw err;
		}
		console.log("已写入文件");
	});
	fs.writeFile('result.txt',this.body + '\n',{'flag':'a'},function(err){
		if(err){
			throw err;
		}
		console.log("已写入文件");
	});
	this.write(this.func,'OK');
};

Server.prototype.processGateEvent = function(data) {
	var r0 = data;
	var r = [];
    var self = this;

    // 信息条数
    var itemCount = parseInt(r0.slice(0, 2), 16);
	r0 = r0.slice(2,r0.length);

    for ( var itemIndex = 0; itemIndex < itemCount; itemIndex ++ ) {
		r.push(r0.slice(0,39));
        r0 = r0.slice(39, r0.length);
    }

    var deviceId = this.id.trim();
    r.forEach(function(rawRecord) {
        // TODO: parse serialId
        var serialId = paddingZero(rawRecord.slice(0, 20).trim(), 8);
        var method = rawRecord.slice(32, 33);
        var year = Number('20' + rawRecord.slice(20, 22));
        var month = Number(rawRecord.slice(22, 24));
        var date = Number(rawRecord.slice(24, 26));
        var hour = Number(rawRecord.slice(26, 28));
        var minute = Number(rawRecord.slice(28, 30));
        var second = Number(rawRecord.slice(30, 32));

        var time = new Date(year, month - 1, date, hour, minute, second);

        console.log(util.format('校园卡编号：%s, 时间：%s', serialId, time));
        if ( method == '1' ) {
            console.log('进校');
            self.enterSchool(deviceId, serialId, time);
        }
        else if ( method == '2' ) {
            console.log('出校');
            self.exitSchool(deviceId, serialId, time);
        }
    });
}

Server.prototype.getTime = function(){
	var t = new Date();
	var yy = t.getFullYear();
	var mm = t.getMonth()+1;
	if(mm<10)
		mm = '0'+mm;
	var dd = t.getDate();
	if(dd<10)
		dd = '0'+dd;
	var hh = t.getHours();
	if(hh<10)
		hh = '0'+hh;
	var mi = t.getMinutes();
	if(mi<10)
		mi = '0'+mi;
	var ss = t.getSeconds();
	if(ss<10)
		ss = '0'+ss;
	var dateStr = ""+yy+mm+dd+hh+mi+ss;
	console.log(dateStr);
	return dateStr ;	
};

var proxy = net.createServer(function(client) {
    console.log('Client connected');
    var clientConnected = true;
    var serverConnected = false;
    var chunkData = "";
    client.on('data', function(chunk) {
		// todo
		//fs.writeFile('result.txt',chunk.toString(),{'flag':'a'},function(err){
		//	if(err){
		//		throw err;
		//	}
		//	console.log("已写入文件");
		//});
		console.log("============="+new Date()+"============");
        console.log('DATA ' + client.remoteAddress + ': '+chunk);
		if(chunk.toString().slice(0,3)=="TPJ"){
			if(chunkData.length>0){
				var r = dataParse(chunkData);
				if(r){
					console.log(r);
					new Server(r,client).handle();
				}
			}
			chunkData = chunk.toString();
		}else{
			if(chunkData.length>0){
				chunkData = chunkData + chunk.toString();
			}
		}

    });
    client.on('close', function(had_error) {
        console.log('Client closed ' + (had_error ? 'unexpectedly' : 'normally'));
    });
    client.on('error', function(err) {
        console.log('Client error: ' + err);
    });
});

String.prototype.repeat = function(count) {
    var result = this;
    for ( var i = 1; i < count; i ++ ) {
        result += this;
    }

    return result;
};

function paddingZero(number, width) {
    var numberString = String(number);
    if ( numberString.length < width ) {
        numberString = '0'.repeat(width - numberString.length) + numberString;
    }

    return numberString;
}

var testMode = 'server';
if ( process.argv[2] ) {
    testMode = process.argv[2];
}

if ( testMode != 'test' ) {
    proxy.listen(listenConf.port, listenConf.listenHost, function(){
        console.log('Proxy listening on ' + listenConf.listenHost + ':' + listenConf.port);
    });
}
else {
    var server = new Server();
    var lines = fs.readFileSync('test_data.txt').toString().split('\n');
    console.log(lines);
    lines.forEach(function(line, lineIndex) {
        if ( lineIndex % 2 == 0 ) {
            server.id = line;
        }
        else {
            server.processGateEvent(line);
        }
    });
}
